package com.thingple.rodbell.packet;

import android.util.Log;

import com.thingple.rodbell.cmd.HandleState;

public abstract class PacketHandler extends AsyncBuffer {

    private static final String TAG = PacketHandler.class.getName();

    private static final byte PacketHead = (byte) 0xA0;

    protected HandleState state;

    private int packetLength = 0;

    protected final byte[] pcRaw = new byte[2];

    /**
     * process: <br/>
     * 按照state顺序依次执行. <br/>
     * 每个流程执行完之后返回buf的状态,<br/>
     * 即:buf里的数据是否足够下一个流程使用,<br/>
     * 如果buf中数据不足, 就从队列里填充buf一次
     */
    protected void process() {

        boolean bufOk;
        switch (state) {
            case Start:
                bufOk = handleStart();
                break;
            case Head:
                bufOk = handlePacketHeader();
                break;
            case Length:
                bufOk = handlePacketLength();
                break;
            case Body:
                bufOk = handlePacketBody();
                break;
            case Done:
                bufOk = handleDone();
                break;
            default:
                bufOk = true;
        }
        if (!bufOk) {
            // more data -> buf
            prepareRaw();
        }
    }

    private boolean handleStart() {
        // TODO init
        packetLength = 0;
        state = HandleState.Head; // 处理packet长度
        return true;
    }

    /**
     * 每次从buf中取出一个字节，如果不是head就忽略，知道读取到head
     */
    private boolean handlePacketHeader() {
        if (buf.size() < 1) {
            return false;
        }
        byte b = buf.get();
        if (b != PacketHead) { // 不是packet head，应该忽略
            return true;
        }
        state = HandleState.Length; // 处理packet长度
        return true;
    }

    /**
     * 从buf中取出一个字节，计算报文体的长度length(byte)
     */
    private boolean handlePacketLength() {
        if (buf.size() < 1) {
            return false;
        }
        byte b = buf.get();
        packetLength = b & 0xFF;
        state = HandleState.Body; // 处理packet长度
        return true;
    }

    private boolean handlePacketBody() {
        if (buf.size() < packetLength) {
            return false;
        }
        byte[] packetBody = buf.get(packetLength);
        try {
            handleLogic(packetBody);// cmd logic
        } catch (Exception e) {
            if (debug) {
                Log.d(TAG, "logic err:" + e.getMessage());
                e.printStackTrace();
            }
        }

        state = HandleState.Done;
        return true;
    }

    protected boolean calcSum(byte[] packetBody) {
        // TODO
        int c = packetBody[packetBody.length - 1] & 0xff;
        if (debug) {
            Log.d(TAG, "check:" + c);
        }
        return true;
    }

    private boolean handleDone() {
        // TODO 什么也不做？
        state = HandleState.Start; // 处理packet长度
        return true;
    }

    protected abstract void handleLogic(byte[] packetBody);
}
